use std::{collections::HashMap, path::Path};
use serde::{Serialize, Deserialize};
use std::io::{ErrorKind, Write, Read};
use bincode::{deserialize, serialize};
use crate::utils::calc_md5;

const BLOCK_SIZE : usize = 512;

#[derive(Serialize, Deserialize)]
pub struct Vile {
    pub version: u32,
    pub hash: String,
    pub parts: Vec<String>,
}

#[derive(Serialize, Deserialize)]
pub struct StorageFile {
    pub tags: String,
    pub datas: HashMap<String, Vec<u8>>,
    pub viles: Vec<Vile>,
}

impl StorageFile {
    pub fn new(tags: String) -> StorageFile {
        let result = StorageFile::load_object(tags.clone());
        match result {
            Ok(obj) => obj,
            Err(_) => {
                let new_obj = StorageFile {
                    tags: tags.clone(),
                    datas: HashMap::new(),
                    viles: Vec::new(),
                };
                new_obj
            }
        }
    }

    pub fn add_data(&mut self, data: &[u8]) -> (bool, Option<String>) {
        let hash = calc_md5(data);

        if let Some(last_vife) = self.viles.last() {
            if last_vife.hash == hash {
                return (true, Some("无需更新".to_string()));
            }
        }
        let version = if self.viles.is_empty() {
            1
        } else {
            self.viles.last().unwrap().version + 1
        } ;
        let mut parts = Vec::new();
        let mut start = 0;
        while start < data.len() {
            let end = (start + BLOCK_SIZE).min(data.len());
            let block = &data[start..end];
            let block_md5 = calc_md5(block);

            parts.push(block_md5.clone());
            self.datas.insert(block_md5, block.to_vec());

            start = end;
        }

        let vile = Vile {
            version,
            hash,
            parts,
        };
        self.viles.push(vile);
        self.save_object().unwrap();
        (true, None)
    }

    pub fn get_data(&self, ver: u32) -> Option<Vec<u8>> {
        let target_verfile: Option<&Vile> = self.viles.iter().find(|v| v.version == ver);
        if let Some(verfile) = target_verfile {
            let mut ctx = Vec::new();
            for hash in verfile.parts.iter() {
                if let Some(block_data) = self.datas.get(hash) {
                    ctx.extend_from_slice(block_data);
                } else {
                    return None;
                }
            }
            return Some(ctx);
        }
        None
    }

    pub fn get_last_data(&self) -> Option<Vec<u8>> {
        let mut ver = 1;
        if self.viles.len() > 0 {
            ver = self.viles.last().unwrap().version;
        }
        self.get_data(ver)
    }

    pub fn save_object(&self) -> Result<(), std::io::Error> {
        if self.tags.is_empty() {
            return Err(std::io::Error::new(
                ErrorKind::InvalidInput,
                "tags字段不能为空，无法生成文件名",
            ));
        }
        let file_name = calc_md5(self.tags.as_bytes()) + ".hex";
        let serialized_data = serialize(self).unwrap();
        let mut file = std::fs::OpenOptions::new()
           .write(true)
           .create(true)
           .open(&file_name)?;
        file.write_all(&serialized_data)?;
        Ok(())
    }

    pub fn load_object(tags : String) -> Result<StorageFile, std::io::Error> {
        let file_name = calc_md5(tags.as_bytes()) + ".hex";
        let path = Path::new(&file_name);
        if !path.exists() {
            return  Err(std::io::Error::new(
                ErrorKind::NotFound,
                "文件不存在",
            ));
        }
        let mut file = std::fs::OpenOptions::new()
           .read(true)
           .open(&file_name)?;
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer)?;
        deserialize(&buffer).map_err(|e| std::io::Error::new(ErrorKind::InvalidInput, e))
    }
}